package com.lhl.jwt.security.providers;


import cn.hutool.crypto.SecureUtil;
import cn.hutool.json.JSONUtil;
import com.lhl.jwt.domain.dto.PayloadDTO;
import com.lhl.jwt.security.define.JwtConstant;
import com.lhl.jwt.security.service.JwtUserDetailsService;
import com.lhl.jwt.security.token.JwtAuthenticationToken;
import com.lhl.jwt.util.JwtUtil;
import com.nimbusds.jose.JOSEException;
import com.nimbusds.jwt.SignedJWT;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.util.Assert;

import java.text.ParseException;


/**
 * jwt认证主要逻辑
 * @author zhangyf
 * @date 2019年8月16日
 */
@Slf4j
public class JwtAuthenticationProvider implements AuthenticationProvider, InitializingBean {

	private final JwtUserDetailsService userDetailsService;

	public JwtAuthenticationProvider(JwtUserDetailsService userDetailsService) {
		this.userDetailsService = userDetailsService;
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		Assert.notNull(this.userDetailsService, "A UserDetailsService must be set");
	}

	@Override
	public Authentication authenticate(Authentication authentication) throws AuthenticationException {
		SignedJWT jwt = ((JwtAuthenticationToken) authentication).getToken();
		Assert.notNull(jwt, JwtConstant.TOKEN_NOT_EMPTY);
		PayloadDTO payloadDTO = null;
		try {
			log.debug("token=={}", JSONUtil.toJsonPrettyStr(jwt.getJWTClaimsSet()));
			payloadDTO = JwtUtil.getPayLoadByToken(jwt.getParsedString(), SecureUtil.md5(jwt.getJWTClaimsSet().getSubject()));
		} catch (ParseException | JOSEException e) {
			e.printStackTrace();
		}
		//从缓存或数据库中获取user对象
		String username = payloadDTO.getUsername();
		UserDetails user = userDetailsService.loadUserByUsername(username);
		if (user == null) {
			return null;
		}
		JwtAuthenticationToken token = new JwtAuthenticationToken(user, jwt, user.getAuthorities());
		return token;
	}

	@Override
	public boolean supports(Class<?> authentication) {
		return authentication.isAssignableFrom(JwtAuthenticationToken.class);
	}

	protected String getSalt(String username) {
		String salt = userDetailsService.getSalt(username);
		if (StringUtils.isBlank(salt)) {
			salt = JwtUtil.TOKEN_SECRET;
		}
		return salt;
	}
	
}
